package cn.smile.business.basic.impl;

import cn.smile.bean.dto.basic.*;
import cn.smile.bean.dto.core.SysUserDTO;
import cn.smile.bean.entity.basic.TopUpBill;
import cn.smile.bean.form.basic.bill.QueryTopUpForm;
import cn.smile.bean.form.basic.bill.TopUpAddForm;
import cn.smile.bean.form.basic.member.QueryMemberForm;
import cn.smile.bean.form.basic.member.UpdateBalanceForm;
import cn.smile.bean.form.basic.voucher.AddVoucherMemberForm;
import cn.smile.bean.form.core.user.QueryUserForm;
import cn.smile.business.basic.IMemberService;
import cn.smile.business.basic.IMyShopService;
import cn.smile.business.basic.ITopUpBillService;
import cn.smile.business.basic.IVoucherMemberService;
import cn.smile.business.core.ISysUserService;
import cn.smile.commons.constant.CommonConstant;
import cn.smile.commons.constant.NumberConstant;
import cn.smile.commons.domain.BaseServiceImpl;
import cn.smile.commons.enums.basic.BalanceOperateEnum;
import cn.smile.commons.enums.basic.MemberStatusEnum;
import cn.smile.commons.enums.basic.MiniProjectCountEnum;
import cn.smile.commons.exceptions.BusinessException;
import cn.smile.commons.response.MyResponseCode;
import cn.smile.repository.basic.TopUpBillMapper;
import cn.smile.utils.BeanCopy;
import cn.smile.utils.DateFormatUtil;
import cn.smile.utils.UserUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import jakarta.annotation.Resource;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;

@Slf4j
@Service
public class TopUpBillServiceImpl extends BaseServiceImpl<TopUpBillMapper, TopUpBill> implements ITopUpBillService {

    @Resource
    private IMemberService memberService;
    @Resource
    private IMyShopService shopService;
    @Resource
    private ISysUserService userService;
    @Resource
    private IVoucherMemberService vouMemService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean addTopUp(TopUpAddForm form) {
        log.info("[TopUpBillServiceImpl].[addTopUp] ------> 新增充值账单 Start, form = {}", JSON.toJSONString(form));
        this.checkParams(form);
        MyShopDTO shop = shopService.getMyShop();
        TopUpBill entity = BeanCopy.copyBean(form, TopUpBill.class);
        super.addBaseCol(entity);
        entity.setShopId(shop.getId());
        entity.setBillTime(LocalDateTime.now());
        entity.setOperateUserId(UserUtil.getUserInfo().getId());
        int insertNum = baseMapper.insert(entity);
        if (insertNum > NumberConstant.ZERO) {
            //保存账户余额
            UpdateBalanceForm balanceForm = new UpdateBalanceForm();
            balanceForm.setMemberId(entity.getMemberId());
            balanceForm.setAmount(entity.getTopUpPrice());
            balanceForm.setGiftPrice(entity.getGiftPrice());
            BigDecimal finalAmount = memberService.updateBalance(balanceForm, BalanceOperateEnum.TOP_UP);
            log.info("更新会员余额完成, 最终金额: {}", finalAmount.toString());
            // 保存账户代金券
            if (!CollectionUtils.isEmpty(form.getVoucherList())) {
                for (String voucherId : form.getVoucherList()) {
                    AddVoucherMemberForm addForm = new AddVoucherMemberForm();
                    addForm.setMemberId(entity.getMemberId());
                    addForm.setVoucherId(voucherId);
                    addForm.setTopUpId(entity.getId());
                    Boolean addFlag = vouMemService.addInfo(addForm);
                    log.info("代金券[{}] 保存结果: {}", voucherId, addFlag);
                }
            }
        }
        log.info("[TopUpBillServiceImpl].[addTopUp] ------> 新增充值账单 End, insertNum = {}", insertNum);
        return insertNum > NumberConstant.ZERO;
    }

    @Override
    public BigDecimal countTopUpAmount(MiniProjectCountEnum countEnum) {
        Date nowDate = new Date();
        String startTime = DateFormatUtil.getCountStartTime(nowDate, countEnum);
        String startEnd = DateFormatUtil.parseDateToStr(nowDate, DateFormatUtil.TO_DATE_END);
        return this.countTopUpAmount(startTime, startEnd);
    }

    @Override
    public BigDecimal countTopUpAmount(String timeStart, String timeEnd) {
        log.info("[TopUpBillServiceImpl].[countTopUpAmount] ------> 统计充值金额 Start, timeStart = {}, timeEnd = {}", timeStart, timeEnd);
        BigDecimal todayAmount = CommonConstant.DEFAULT_PRICE;
        MyShopDTO shop = shopService.getMyShop();
        LambdaQueryWrapper<TopUpBill> qw = new QueryWrapper<TopUpBill>().lambda().eq(TopUpBill::getDeleted, Boolean.FALSE).eq(TopUpBill::getShopId, shop.getId());
        qw.ge(TopUpBill::getBillTime, timeStart);
        qw.le(TopUpBill::getBillTime, timeEnd);
        List<TopUpBill> baseList = baseMapper.selectList(qw);
        if (!CollectionUtils.isEmpty(baseList)) {
            for (TopUpBill entity : baseList) {
                todayAmount = todayAmount.add(entity.getTopUpPrice());
            }
        }
        log.info("[TopUpBillServiceImpl].[countTopUpAmount] ------> 统计充值金额 End, totalAmount = {}", todayAmount);
        return todayAmount;
    }

    @Override
    public IPage<TopUpBillDTO> getPage(QueryTopUpForm form) {
        log.info("[TopUpBillServiceImpl].[getPage] ------> 分页查询充值账单 Start, form = {}", JSON.toJSONString(form));
        LambdaQueryWrapper<TopUpBill> qw = this.getQueryParams(form);
        Page<TopUpBill> basePage = baseMapper.selectPage(form.queryPage(), qw);
        IPage<TopUpBillDTO> dataPage = BeanCopy.copyPage(basePage, TopUpBillDTO.class);
        this.setDetail(dataPage.getRecords());
        log.info("[TopUpBillServiceImpl].[getPage] ------> 分页查询充值账单 End");
        return dataPage;
    }

    @Override
    public List<TopUpBillDTO> getList(QueryTopUpForm form) {
        log.info("[TopUpBillServiceImpl].[getList] ------> 列表查询充值账单 Start, form = {}", JSON.toJSONString(form));
        LambdaQueryWrapper<TopUpBill> qw = this.getQueryParams(form);
        List<TopUpBill> baseList = baseMapper.selectList(qw);
        List<TopUpBillDTO> dataList = BeanCopy.copyList(baseList, TopUpBillDTO.class);
        this.setDetail(dataList);
        log.info("[TopUpBillServiceImpl].[getList] ------> 列表查询充值账单 End");
        return dataList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean delTopUp(String id) {
        log.info("[TopUpBillServiceImpl].[delTopUp] ------> 会员充值记录退款 Start, id = {}", id);
        if (ObjectUtils.isEmpty(id)) {
            throw new BusinessException(MyResponseCode.TOP_UP_ID_NULL_ERROR);
        }
        TopUpBill entity = baseMapper.selectOne(new QueryWrapper<TopUpBill>().lambda().eq(TopUpBill::getDeleted, Boolean.FALSE).eq(TopUpBill::getId, id));
        if (ObjectUtils.isEmpty(entity)) {
            throw new BusinessException(MyResponseCode.RESULT_DATA_NONE);
        }
        super.delBaseCol(entity);
        int updateNum = baseMapper.updateById(entity);
        if (updateNum > NumberConstant.ZERO) {
            UpdateBalanceForm balanceForm = new UpdateBalanceForm();
            balanceForm.setMemberId(entity.getMemberId());
            balanceForm.setAmount(entity.getTopUpPrice());
            balanceForm.setGiftPrice(entity.getGiftPrice());
            memberService.updateBalance(balanceForm, BalanceOperateEnum.EXPENSE);
            vouMemService.delByTopUpId(id);
        }
        log.info("[TopUpBillServiceImpl].[delTopUp] ------> 会员充值记录退款 End, updateNum = {}", updateNum);
        return updateNum > NumberConstant.ZERO;
    }

    @Override
    public Long countContinueMemberNum(String timeStart, String timeEnd) {
        log.info("[TopUpBillServiceImpl].[countContinueMemberNum] ------> 统计续卡会员数量 Start, timeStart = {}, timeEnd = {}", timeStart, timeEnd);
        QueryTopUpForm topUpForm = new QueryTopUpForm();
        topUpForm.setQueryTimeStart(timeStart);
        topUpForm.setQueryTimeEnd(timeEnd);
        topUpForm.setFirstPreStore(Boolean.FALSE);
        List<TopUpBillDTO> billList = this.getList(topUpForm);
        Set<String> memberIds = new HashSet<>(NumberConstant.EIGHT);
        if (!CollectionUtils.isEmpty(billList)) {
            billList.forEach(bill -> memberIds.add(bill.getMemberId()));
        }
        int memberCount = CollectionUtils.isEmpty(memberIds) ? NumberConstant.ZERO : memberIds.size();
        log.info("[TopUpBillServiceImpl].[countContinueMemberNum] ------> 统计续卡会员数量 End, memberCount = {}", memberCount);
        return Long.parseLong(String.valueOf(memberCount));
    }

    @Override
    public TopUpBillDTO getBillById(String id) {
        log.info("[TopUpBillServiceImpl].[getBillById] ------> ID查询充值账单详情 Start, id = {}", id);
        TopUpBill baseEntity = baseMapper.selectOne(new QueryWrapper<TopUpBill>().lambda().eq(TopUpBill::getDeleted, Boolean.FALSE).eq(TopUpBill::getId, id));
        if (ObjectUtils.isEmpty(baseEntity)) {
            throw new BusinessException(MyResponseCode.RESULT_DATA_NONE);
        }
        TopUpBillDTO dto = BeanCopy.copyBean(baseEntity, TopUpBillDTO.class);
        this.setDetail(Lists.newArrayList(dto));
        log.info("[TopUpBillServiceImpl].[getBillById] ------> ID查询充值账单详情 End");
        return dto;
    }

    /**
     * 写入其他信息
     *
     * @param dataList 数据集合
     */
    @SuppressWarnings("DuplicatedCode")
    private void setDetail(List<TopUpBillDTO> dataList) {
        if (!CollectionUtils.isEmpty(dataList)) {
            Set<String> memberIds = Sets.newHashSet();
            Set<String> userIds = Sets.newHashSet();
            List<String> ids = Lists.newArrayList();
            dataList.forEach(dto -> {
                ids.add(dto.getId());
                if (!ObjectUtils.isEmpty(dto.getMemberId())) {
                    memberIds.add(dto.getMemberId());
                    if (!ObjectUtils.isEmpty(dto.getOperateUserId())) {
                        userIds.add(dto.getOperateUserId());
                    }
                }
            });
            //统计代金券数量
            Map<String, Integer> countVoucherMap = vouMemService.countNumByTopUpIds(ids);
            //查询会员信息
            Map<String, MemberInfoDTO> memberMap = Maps.newHashMap();
            if (!CollectionUtils.isEmpty(memberIds)) {
                QueryMemberForm memberForm = new QueryMemberForm();
                memberForm.setIds(Lists.newArrayList(memberIds));
                List<MemberInfoDTO> memberList = memberService.getMemberList(memberForm);
                if (!CollectionUtils.isEmpty(memberList)) {
                    for (MemberInfoDTO dto : memberList) {
                        memberMap.put(dto.getId(), dto);
                    }
                }
            }
            //查询用户信息
            QueryUserForm queryForm = new QueryUserForm();
            queryForm.setIds(Lists.newArrayList(userIds));
            Map<String, SysUserDTO> userMap = userService.getMyShopUserMap(queryForm);
            //写入会员信息
            for (TopUpBillDTO dto : dataList) {
                dto.setVoucherNum(countVoucherMap.getOrDefault(dto.getId(), NumberConstant.ZERO));
                dto.setSimplifyBillTime(dto.getBillTime());
                if (ObjectUtils.isEmpty(dto.getMemberId()) || !memberMap.containsKey(dto.getMemberId())) {
                    continue;
                }
                MemberInfoDTO member = memberMap.get(dto.getMemberId());
                dto.setMemberName(member.getMemberName());
                dto.setMemberNo(member.getMemberNo());
                dto.setFirstPreStoreText(dto.getFirstPreStore() ? "首充" : "续费");
                if (!ObjectUtils.isEmpty(dto.getOperateUserId()) && userMap.containsKey(dto.getOperateUserId())) {
                    dto.setOperateUser(userMap.get(dto.getOperateUserId()));
                    dto.setOperateUserName(userMap.get(dto.getOperateUserId()).getNickName());
                }
            }
        }
    }

    /**
     * 组装查询对象
     *
     * @param form 查询参数
     * @return 查询对象
     */
    @SuppressWarnings("DuplicatedCode")
    private LambdaQueryWrapper<TopUpBill> getQueryParams(QueryTopUpForm form) {
        LambdaQueryWrapper<TopUpBill> qw = new QueryWrapper<TopUpBill>().lambda().eq(TopUpBill::getDeleted, Boolean.FALSE);
        MyShopDTO shop = shopService.getMyShop();
        qw.eq(TopUpBill::getShopId, shop.getId());
        if (!ObjectUtils.isEmpty(form.getNameOrNo())) {
            QueryMemberForm memberForm = new QueryMemberForm();
            memberForm.setNameOrNo(form.getNameOrNo());
            List<MemberInfoDTO> memberList = memberService.getMemberList(memberForm);
            List<String> memberIds = Lists.newArrayList();
            if (!CollectionUtils.isEmpty(memberList)) {
                for (MemberInfoDTO dto : memberList) {
                    memberIds.add(dto.getId());
                }
            }
            if (CollectionUtils.isEmpty(memberIds)) {
                memberIds.add(UUID.randomUUID().toString());
            }
            qw.in(TopUpBill::getMemberId, memberIds);
        }
        if (!ObjectUtils.isEmpty(form.getQueryTimeStart())) {
            qw.ge(TopUpBill::getBillTime, form.getQueryTimeStart());
        }
        if (!ObjectUtils.isEmpty(form.getQueryTimeEnd())) {
            qw.le(TopUpBill::getBillTime, form.getQueryTimeEnd());
        }
        if (!ObjectUtils.isEmpty(form.getMemberId())) {
            qw.eq(TopUpBill::getMemberId, form.getMemberId());
        }
        if (!ObjectUtils.isEmpty(form.getFirstPreStore())) {
            qw.eq(TopUpBill::getFirstPreStore, form.getFirstPreStore());
        }
        return qw;
    }

    /**
     * 检查参数
     *
     * @param form 请求参数
     */
    private void checkParams(TopUpAddForm form) {
        MemberInfoDTO member = memberService.getBaseMemberById(form.getMemberId());
        if (MemberStatusEnum.ENABLE != MemberStatusEnum.get(member.getStatus())) {
            throw new BusinessException(MyResponseCode.MEMBER_UN_ENABLE_ERROR);
        }
    }
}
